/*
 * customer.cc
 *
 *  Created on: May 30, 2011
 *      Author: peskanda
 */

#include "synch.h"
#include "item.h"
//#include "aisle.h"
#include "sharedDefinitions.h"
#include "locks.h"
#include "customer.h"
#include "homedepot.h"
#include "stockboy.h"


Customers::Customers(int customerID,bool wantsToReturnItems, Store* store, Locks* allTheLocks)
															:_customerID(customerID),
															 _wantsToReturnItems(wantsToReturnItems),
															 _store(store),
															 _allTheLocks(allTheLocks) {

    //We just created a new customer. Lets increase the number of customers in store.
	ASSERT (_store != NULL);
	ASSERT (_allTheLocks != NULL);
	ASSERT (_allTheLocks->_occupancyLock != NULL);
	_allTheLocks->_occupancyLock->Acquire();
	_allTheLocks->_customersInStore ++;
	_allTheLocks->_occupancyLock->Release();
	// initializes the shoppingList with 1..10 randomly generated items.
	_shoppingListSize = (rand()%MAX_SHOPPING_LIST)+1;
	_shoppingList = new int[_shoppingListSize];
	for (int i=0; i < _shoppingListSize; i++)
	{
		_shoppingList[i] = rand()% MAX_ITEMS; //pick a random item from our items catalog
	}
	if (_wantsToReturnItems==false)
	{
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] wants to buy [%i] no.of items.\n", _customerID,_shoppingListSize);
#endif
	}
	else
	{
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] needs to return [%i] no.of items.\n", _customerID,_shoppingListSize);
#endif
	}
}

Customers::~Customers()
{
	//LeaveStore();
}
/*
 * Main function for customer which organized his/her activities
 */
void Customers::DoShopping() {
    if (_wantsToReturnItems == false)
	{
		//We just got into the store, lets collect our items
		CollectShoppingListItems();
		//Now all of the items have been collected. lets check out
	}
#ifndef IGNORE_CLERKS
    if (_allTheLocks->testNo == 1)
    {
		///////////////////////////////////////////////////////
		// Test Case 1- Wait till all of the customers are ready to get into
		//				the lines
		///////////////////////////////////////////////////////
    	_allTheLocks->t1_l1->Acquire();
    	(_allTheLocks->t1_numberOfCustomersReadyToGetIntLines)++;
    	_allTheLocks->t1_c1->Wait(_allTheLocks->t1_l1);
    	_allTheLocks->t1_l1->Release();
    }
	//we need to get into the shortest line
	//and wait till its our turn.
	int clerkID = GetIntoTheShortestClerkLine();
	if (_allTheLocks->testNo == 1)
	{
		///////////////////////////////////////////////////////
		// Test Case 1
		///////////////////////////////////////////////////////
		_allTheLocks->t1_selectedLines[_customerID]= clerkID;
		_allTheLocks->t1_done->V();
		return;
	}
	//Now its our turn. Lets provide our items to clerk
	ProvideTheItemsToClerk(clerkID);
	//Clerk lock is already acquired in previous step
	//so we are guaranteed we have the attention of clerk
	//lets pay the amount due or take our refund
	TransferPayment(clerkID);
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLock[%i]->Release()\n", _customerID, clerkID);
#endif
	_allTheLocks->_clerkLock[clerkID]->Release();
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLock[%i]->Release() Done!\n", _customerID, clerkID);
#endif

#endif
	LeaveStore();

}

void Customers::CollectShoppingListItems() {
	for (int shoppingListIndex = 0; shoppingListIndex < _shoppingListSize; shoppingListIndex++) {
		int currentItemIDToPickup = _shoppingList[shoppingListIndex];
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i: Collecting item index# %i Num# %i \n", _customerID, shoppingListIndex, currentItemIDToPickup);
#endif
		int aisleNumber= LookForAisleNumber(currentItemIDToPickup);
		//by now we know what is our aisleNumber
		//go to the aisle (this can be simply a tele-port to that aisle)
		ASSERT (aisleNumber >=0 && aisleNumber < MAX_AISLES);
		Aisle* aisleToSearch = _store->aisles[aisleNumber];
#ifndef IGNORE_STOCKBOYS
		bool couldPickupItem = false;
		while (! couldPickupItem)
		{
			couldPickupItem = PickupItem(aisleNumber, currentItemIDToPickup);
		}
#endif
	}
}

/*
 * Returns the aisle number for a given item ID
 * 75% of the times customer can immediately know the aisle id, but
 * 25% of the times he needs to ask this from a stockboy
 */
int Customers::LookForAisleNumber(int itemID)
{
#ifdef IGNORE_STOCKBOYS
	return _store->GetAisleNumber(itemID);
#endif
	int aisleNumber=NOT_FOUND;
	//lets find out if we are lucky enough to know where the item is
	int chanceToFindTheAisle = (rand()%100)+ 1;
	// 75% of times correctly can find the aisle number
	if (chanceToFindTheAisle <= 75) {
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i: Can find the aisle ourself \n", _customerID);
#endif
		aisleNumber = _store->GetAisleNumber(itemID);
	}
	else {
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] is not able to find item [%i] and is searching for StockBoy.\n", _customerID, itemID);
#endif
		//25% of times he/she does not know the aisleNumber.
		//lets look in aisles to find a stock boy and ask him the aisle number.
		//first we need to lock statuses of stockBoys
		_allTheLocks->_stockBoysStatusLock->Acquire();
		int aisleThatWeFoundTheStockBoyIn=NOT_FOUND;
		//we have to go through aisles one by one to find a stock boy
		for(int currentAisleIndex=0; currentAisleIndex < MAX_AISLES; currentAisleIndex++) {
			//Lets see if any stock boy is in current aisle
			for(int currentStockBoyIndex=0; currentStockBoyIndex < MAX_STOCKBOYS; currentStockBoyIndex++) {
				int currentStockBoyStatus = _allTheLocks->_stockBoysStatus[currentStockBoyIndex];
				if (currentStockBoyStatus == currentAisleIndex) {
					aisleThatWeFoundTheStockBoyIn = currentAisleIndex;
					break;
				}
			}
			if (aisleThatWeFoundTheStockBoyIn != NOT_FOUND)
				break;
		}
		if (aisleThatWeFoundTheStockBoyIn== NOT_FOUND) {
#ifdef PRINT_EXTRA_LOG_CUSTOMER
			printf("CUSTOMER# %i: LookForAisleNumber(itemID# %i) Couldn't find any stock boy in aisles! SERVICE BUTTUN RINGED and wait for stock boy!\n", _customerID, itemID);
#endif
			//Couldn't find any stock boys in any aisle, so we should form a line
			//in service area
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n", _customerID);
#endif
			aisleThatWeFoundTheStockBoyIn = SERVICE_AREA_LINE; //SERVICE_AREA_LINE = MAX_AISLES = last index of the array
		}
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		else
		{
			printf("CUSTOMER# %i: Waiting for a stock boy in aisle# %i \n", _customerID, aisleThatWeFoundTheStockBoyIn);
		}
#endif
		Lock* customersWaiting = _allTheLocks->_customersWaitingInAisleToAskQuestionLock[aisleThatWeFoundTheStockBoyIn];
		Condition* customersWaitingCondition = _allTheLocks->_customersWaitingInAisleToAskQuestionCV[aisleThatWeFoundTheStockBoyIn];
		_allTheLocks->_stockBoysStatusLock->Release();
		customersWaiting->Acquire();
		//Please notice that the following function returns a pointer so we can easily increment its content
		_allTheLocks->_customersWaitingInAisleToAskQuestionMV[aisleThatWeFoundTheStockBoyIn]++;
		//Lets wait for stock boy to finish his task.
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i: LookForAisleNumber(itemID# %i) Waiting for a stock boy to help us\n", _customerID, itemID);
#endif
		customersWaitingCondition->Wait(customersWaiting);
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i: LookForAisleNumber(itemID# %i) just got woekn up by a stock boy\n", _customerID, itemID);
#endif
		//a stock boy just woke us up to answer our question. We need to search for that stock boy.
		//as convention, once a stock boy wakes a customer up, he needs to add MAX_AISLES to his
		//status so the customer can find him. i.e. now we need to search for a stock boy
		//with his status set to (aisleThatWeFoundTheStockBoyIn+NUM_CUSTOMERS_WAIT_LINES_FOR_STOCKBOYS)
		int currentStockBoyIndex  = _allTheLocks->_stockBoyIdInAisleToAnswerQuestionMV[aisleThatWeFoundTheStockBoyIn];
		ASSERT (currentStockBoyIndex < MAX_STOCKBOYS); //We assume we must find a stockboy ready for help
		Lock* questionLock = _allTheLocks->_customerItemQuestionLock[currentStockBoyIndex];
		Lock* answerLock = _allTheLocks->_stockBoyAisleAnswerLock[currentStockBoyIndex];
		Condition* questionCondition=_allTheLocks->_customerItemQuestionCV[currentStockBoyIndex];
		Condition* answerCondition= _allTheLocks->_stockBoyAisleAnswerCV[currentStockBoyIndex];
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] is asking for assistance from StockBoy [%i]\n", _customerID, currentStockBoyIndex);
#endif
		customersWaiting->Release();
		questionLock->Acquire();
		//currentStockBoyIndex is who we can ask our question from.
		//we need to ask our question through locking a shared monitor variable.
		//This needs to happen before we release the customersWaitingInAisleToAskQuestionLock, because
		//we need to make other customers wait till our question is being answered.
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i locked the question for Stockboy %i\n", _customerID, currentStockBoyIndex);
#endif
		_allTheLocks->_customerItemQuestionMV[currentStockBoyIndex]= itemID;
		_allTheLocks->_customerID_AskingQuestionMV[currentStockBoyIndex]=_customerID;
		questionCondition->Signal(questionLock);
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i put the item#%i in the question place for Stockboy %i\n", _customerID,itemID, currentStockBoyIndex);
#endif
		//We asked our question, now we need to wait till stock boy receives the answer, and hands over the aisle number
		answerLock->Acquire();
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i acquired the answer lock for Stockboy %i\n", _customerID, currentStockBoyIndex);
#endif
		questionLock->Release();
#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i waiting for answer from Stockboy %i\n", _customerID, currentStockBoyIndex);
#endif
		answerCondition->Wait(answerLock);
		//Stock boy just provided the aisle number, lets grab it
		aisleNumber = _allTheLocks->_stockBoyAisleAnswerMV[currentStockBoyIndex];
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] got aisle [%i] from StockBoy [%i]\n", _customerID,aisleNumber, currentStockBoyIndex);
#endif
		answerLock->Release();
	}
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: LookForAisleNumber(itemID# %i) the aisle# is %i \n", _customerID, itemID, aisleNumber);
#endif
	return aisleNumber;
}

/*
 * Given a specific item id, this function will put a request on re stocking
 * specific item.
 */
bool Customers::PickupItem(int aisleNumber, int itemId) {
#ifdef IGNORE_STOCKBOYS
	return true;
#endif
	Lock* itemLock  = _allTheLocks->_shelfLock[itemId];
	Lock* reStockLock = _allTheLocks->_customerWaitingForReStockLock;
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) Started!\n", _customerID, aisleNumber, itemId);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemLock[%i]->Acquire()!\n", _customerID, itemId);
#endif
	itemLock->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemLock[%i]->Acquire() Done!\n", _customerID, itemId);
#endif

#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) Locked the item\n", _customerID, aisleNumber, itemId);
#endif
	bool couldPickupItem = false;
	do
	{
		couldPickupItem = _store->PickupItem(itemId);
		if (!couldPickupItem)
		{
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemLock[%i]->Release()!\n", _customerID, itemId);
#endif
			itemLock->Release();
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemLock[%i]->Release() Done!\n", _customerID, itemId);
#endif

#ifdef PRINT_EXTRA_LOG_CUSTOMER
			printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) Couldn't pickup item. Lets wait for a stock boy to re stock it.!\n", _customerID, aisleNumber, itemId);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i reStockLock->Acquire()!\n", _customerID);
#endif
			reStockLock->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i reStockLock->Acquire() Done!\n", _customerID);
#endif

#ifdef PRINT_EXTRA_LOG_CUSTOMER
			printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) lets get into the line of customers waiting for re stocking.!\n", _customerID, aisleNumber, itemId);
#endif
			_allTheLocks->_customersWaitingForRestock[itemId]++;
			//lets wait for a stock boy to re stock this item
#ifdef PRINT_EXTRA_LOG_CUSTOMER
			printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) lets wait on this line!\n", _customerID, aisleNumber, itemId);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemCV[reStockLock][%i]->Wait()!\n", _customerID, itemId);
#endif
			_allTheLocks->_itemWaitCV[itemId]->Wait(reStockLock);
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemCV[reStockLock][%i]->Wait() Done!\n", _customerID, itemId);
#endif
			//We just got a signal from stock boy that item is available for pickup
#ifdef PRINT_EXTRA_LOG_CUSTOMER
			printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) just got the signal from stock boy that item is available.\n", _customerID, aisleNumber, itemId);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemLock[%i]->Acquire()!\n", _customerID, itemId);
#endif
			itemLock->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i itemLock[%i]->Acquire() Done!\n", _customerID, itemId);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i restockLock->Release()!\n", _customerID);
#endif
			reStockLock->Release();
#ifdef PRINT_LOCKS_STOCKBOY
			printf("CUSTOMER #%i reStockLock->Release() Done!\n", _customerID);
#endif
		}
	} while(!couldPickupItem);
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: PickupItem(aisle# %i, itemID# %i) Successfully picked up the item!\n", _customerID, aisleNumber, itemId);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
	printf("CUSTOMER #%i itemLock[%i]->Release()!\n", _customerID, itemId);
#endif
	itemLock->Release();
#ifdef PRINT_LOCKS_STOCKBOY
	printf("CUSTOMER #%i itemLock[%i]->Release()Done!\n", _customerID, itemId);
#endif
	return couldPickupItem;
}

/*
 * Finds the shortest line and gets into it; if no clerk in duty will wait for
 * manager to signal a clerk and eventually will get into a line.
 * The customer will wait till its his/her turn (signal receive from clerk).
 * Once he is woken up he will lock the clerk.
 * At the end of this function we are guaranteed that the clerk is locked and ready to service to us.
 */
int Customers::GetIntoTheShortestClerkLine()
{
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: GetIntoTheShortestClerkLine() lets find the shortest line\n", _customerID);
#endif
	Lock* clerkLineLock = _allTheLocks->_clerkLinelock;
	Lock* waitForClerksToReturn = _allTheLocks->_customerNeedsClerkAssitanceLock;
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Acquire()\n", _customerID);
#endif
	clerkLineLock->Acquire();
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Acquire() Done!\n", _customerID);
#endif
	int shortestLineIndex = LookForShortestClerkLine();
	//We need to notify the manager if all of the clerks are on break.
	if (shortestLineIndex == NOT_FOUND)  {
		while (shortestLineIndex == NOT_FOUND)
		{

#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Release()\n", _customerID);
#endif
		clerkLineLock->Release();
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Release() Done!\n", _customerID);
#endif


#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i waitForClerkToReturn->Acquire()\n", _customerID);
#endif
		waitForClerksToReturn->Acquire();
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i waitForClerkToReturn->Acquire() Done!\n", _customerID);
#endif

#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i: GetIntoTheShortestClerkLine() all of the clerks are in break, ask manager to send one for us\n",_customerID);
#endif
		(_allTheLocks->_customersNeedingAsistanceMV)++;
		//Wait for manager so he can tell a clerk to come back to work.
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i customerAssistance[clerkLineLock]->Wait()\n", _customerID);
#endif
		_allTheLocks->_customerNeedsClerkAssitanceCV->Wait(waitForClerksToReturn);
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i customerAssistance[clerkLineLock]->Wait() Done!\n", _customerID);
#endif

#ifdef PRINT_EXTRA_LOG_CUSTOMER
		printf("CUSTOMER# %i: GetIntoTheShortestClerkLine() Just got woken up to get into line\n",_customerID);
#endif
		//Now we can check again for shortest line
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Acquire()\n", _customerID);
#endif
		clerkLineLock->Acquire();
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Acquire() Done!\n", _customerID);
#endif
		shortestLineIndex =_allTheLocks->_clerkIDSignalingToCustomer;//LookForShortestClerkLine();
		}
		(_allTheLocks->_clerkLineLength[shortestLineIndex])++;
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i customerShouldFindClerkCV->Signal()\n", _customerID);
#endif
		_allTheLocks->_customerShouldFindTheClerkCV->Signal(waitForClerksToReturn);
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i waitForClerksToReturn->Release()\n", _customerID);
#endif
		waitForClerksToReturn->Release();
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i waitForClerksToReturn->Release() Done!\n", _customerID);
#endif

	}
	else
	{
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] chose Clerk[%i] with line length of [%i]\n", _customerID,shortestLineIndex, _allTheLocks->_clerkLineLength[shortestLineIndex]);
#endif
		//by now we have found the shortest line. lets stay on the line
		(_allTheLocks->_clerkLineLength[shortestLineIndex])++;
	}
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineCV[%i][clerkLineLock]->Wait()\n", _customerID, shortestLineIndex);
#endif
	_allTheLocks->_clerkLineCV[shortestLineIndex]->Wait(clerkLineLock);
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineCV[%i][clerkLineLock]->Wait() Done!\n", _customerID, shortestLineIndex);
#endif

#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: GetIntoTheShortestClerkLine() Finally! its my turn in line#%i\n", _customerID, shortestLineIndex);
#endif
	//At this point, we just woke up (its our turn) so
	//lets get out of the line and lock the clerk so no one else can interrupt us
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Release()\n", _customerID);
#endif
	clerkLineLock->Release();       //We can safely release this lock, because clerk will not
								 // signal other customers till he is done with current customer
#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLineLock->Release() Done\n", _customerID);
#endif

#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLock[%i]->Acquire()\n", _customerID, shortestLineIndex);
#endif

	_allTheLocks->_clerkLock[shortestLineIndex]->Acquire();

#ifdef PRINT_LOCKS_CLERK
	printf("CUSTOMER# %i clerkLock[%i]->Acquire() Done!\n", _customerID, shortestLineIndex);
#endif

	return shortestLineIndex;
}

int Customers::LookForShortestClerkLine(){
	//The locking is happening outside of this function
	int shortestLineLength = MAX_INT;
	int   shortestLineIndex = NOT_FOUND;
	//find the shortest line
	bool anyClerkOnBreak = false;
	int clerksOnBreak = 0;
	for(int i = 0; i< MAX_CLERKS; i++) {
		if (_allTheLocks->_clerkStatus[i]==CLERK_BREAK)
		{
			clerksOnBreak++;
			anyClerkOnBreak = true;
			continue;
		}
		//then clerk isn't on break
		if (_allTheLocks->_clerkLineLength[i] < shortestLineLength) {
			shortestLineLength = _allTheLocks->_clerkLineLength[i];
			shortestLineIndex = i;
		}
	}
	if (shortestLineLength > 5 && anyClerkOnBreak==true)
	{
		//lets not jump into this line but lets wait for a new clerk to come
		shortestLineIndex = NOT_FOUND;
	}
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	if (shortestLineIndex != NOT_FOUND)
		printf("CUSTOMER# %i: LookForShortestClerkLine() the shortest line is %i with %i customers in it, while there are %i clerks on break.\n", _customerID, shortestLineIndex, shortestLineLength, clerksOnBreak);
#endif
	return shortestLineIndex;
}

/*
 * Provides all of the items to clerk. Clerk is already locked and
 * Waiting for us. At the end of this function we still have the clerk locked
 * but havn't released the clerk lock yet. As a result, clerk is still
 * sleeping waiting for so we declare we are ready for totals
 */
void Customers::ProvideTheItemsToClerk(int clerkID) {
	//clerkLock has already been acquired. Clerk is in sleep and waiting for us to provide
	//the nature of transaction, customer ID, etc and then
	//provide our items one by one.
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: ProvideTheItemsToClerk(clerk#%i) started providing the items\n", _customerID, clerkID);
#endif
	Lock* clerkLock =_allTheLocks->_clerkLock[clerkID];
	Lock* customerLock = _allTheLocks->_customerLock[clerkID];
	_allTheLocks->_customerActionLock->Acquire();
	_allTheLocks->_customerBeingHelped[clerkID] = _customerID;
	_allTheLocks->_customerWantsToScanItems[clerkID] = _wantsToReturnItems;
	_allTheLocks->_customerActionLock->Release();
	//put the items in shared area and signal the clerk, wait for clerk's signal
	//so we can put the next item
	for (int shoppingListIndex = 0; shoppingListIndex < _shoppingListSize; shoppingListIndex++) {
		int currentItemIDToPassToClerk = _shoppingList[shoppingListIndex];
		_allTheLocks->_nextItem[clerkID] = _shoppingList[shoppingListIndex];
		//_allTheLocks->_clerkCV[clerkID]->Signal(clerkLock);
#ifdef PRINT_OUTPUT_CUSTOMER
		printf("Customer [%i] gives item [%i] to Clerk[%i]\n", _customerID,_shoppingList[shoppingListIndex], clerkID);
#endif
		_allTheLocks->_clerkCV[clerkID]->Signal(clerkLock);
		_allTheLocks->_customerCV[clerkID]->Wait(clerkLock);
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: ProvideTheItemsToClerk(clerk#%i) Clerk said he is ready to take the next item\n", _customerID, clerkID);
#endif
	}
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i: ProvideTheItemsToClerk(clerk#%i) Let the clerk know we are done passing items\n", _customerID, clerkID);
#endif
#ifdef PRINT_OUTPUT_CUSTOMER
	printf("Customer [%i] tell Clerk [%i], I have given you all my [%i] items.\n", _customerID, clerkID, _shoppingListSize);
#endif
	_allTheLocks->_nextItem[clerkID] = NOT_FOUND; //No more items to scan
	_allTheLocks->_clerkCV[clerkID]->Signal(clerkLock);
	_allTheLocks->_customerCV[clerkID]->Wait(clerkLock);
}

/*
 * This function first will query the total amount of transaction
 * (either the amount due, or the total refund amount), pay/receives the
 * payments, and takes the receipt. The clerk will be remained locked
 * the whole time in this function.
 */
void Customers::TransferPayment(int clerkID){
	// create local references to shared Locks/CV/MV
	Lock* clerkLock =_allTheLocks->_clerkLock[clerkID];
	Lock* customerLock =_allTheLocks->_customerLock[clerkID];
	Lock* waitForTotalLock = _allTheLocks->_customerWaitForTotalLock[clerkID];
	Condition* waitForTotalCV = _allTheLocks->_customerWaitForTotalCV[clerkID];
	Lock* clerkTransferringMoneyLock = _allTheLocks->_clerkWaitForMoneyLock[clerkID];
	Condition* clerkTransferringMoneyCV = _allTheLocks->_clerkWaitForMoneyCV[clerkID];
	Lock* waitForReceiptLock = _allTheLocks->_customerWaitForReceiptLock[clerkID];
	Condition* waitForReceiptCV = _allTheLocks->_customerWaitForReceiptCV[clerkID];
	Lock* clerkWaitForCustomerLeavingLock = _allTheLocks->_clerkWaitForCustomerLeavingLock[clerkID];
	Condition* clerkWaitForCustomerLeavingCV = _allTheLocks->_clerkWaitForCustomerLeavingCV[clerkID];

	double total = _allTheLocks->_moneyToTransfer[clerkID];
#ifdef PRINT_OUTPUT_CUSTOMER
	if (_wantsToReturnItems)
		printf("Customer [%i] receives [%.2f] from Clerk %i and is now waiting for receipt.\n", _customerID, total,  clerkID);
	else
		printf("Customer [%i] pays [%.2f] to Clerk %i and is now waiting for receipt.\n", _customerID, total,  clerkID);
#endif
	_allTheLocks->_clerkCV[clerkID]->Signal(clerkLock);
	//Wait till clerk gives the receipt
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i, %s: TransferPayment(clerk#%i) Wait for receipt.\n", _customerID, (_wantsToReturnItems)? "Returning": "Purchasing",clerkID);
#endif
	_allTheLocks->_customerCV[clerkID]->Wait(clerkLock);
#ifdef PRINT_OUTPUT_CUSTOMER
	printf("Customer [%i] got receipt from Clerk %i and is now leaving.\n", _customerID, clerkID);
#endif
	//Let the clerk know we pickup our receipt
	_allTheLocks->_clerkCV[clerkID]->Signal(clerkLock);
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i, %s: TransferPayment(clerk#%i) Let the clerk know we got the receipt.\n", _customerID, (_wantsToReturnItems)? "Returning": "Purchasing",clerkID);
#endif
	//clerkLock->Release();
}

void Customers::LeaveStore()
{
#ifdef PRINT_EXTRA_LOG_CUSTOMER
	printf("CUSTOMER# %i, %s: Leaving the store.\n", _customerID, (_wantsToReturnItems)? "Returning": "Purchasing");
#endif
	_allTheLocks->_occupancyLock->Acquire();
	_allTheLocks->_customersInStore --;
	_allTheLocks->_occupancyLock->Release();
	//Lets get rid of our shopping list
	delete _shoppingList;
}
